package com.jsy.testlock.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jsy.testlock.entity.Product;
import com.jsy.testlock.mapper.ProductMapper;
import com.jsy.testlock.service.ProductService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.Random;


/**
 * (Product)表服务实现类
 *
 * @author: SongyangJi
 * @since: 2021-11-30 20:44:05
 * @description:
 */

@Slf4j
@Service("productService")
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    @Resource
    private ProductMapper productMapper;

    private final Random random = new Random();

    /**
     * 模拟数据库事务时间
     */
    private void delay() {
        try {
            Thread.sleep(random.nextInt(100) + 50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean buyNonLock(int id) {
        Product product = productMapper.selectProduct(id);
        if (product.getCount() > 0) {
//            delay();
            productMapper.decr(product);
        }
        return true;
    }

    public boolean buyProductOptimisticWithRetry(int id) {
        final int MAX_RETRY = 999999; // 这里假定是无限重试

        for (int i = 0; i < MAX_RETRY; i++) {
            Product product = productMapper.selectProduct(id);
            if (product.getCount() <= 0) {
                break;
            }
            if (productMapper.decrOptimisticLock(product) == 1) {
                return true;
            }
            delay();
        }
        return false;
    }

    @Override
    public boolean buyProductOptimistic(int id) {
//        delay();
        Product product = productMapper.selectProduct(id);
        if (product.getCount() > 0) {
            return productMapper.decrOptimisticLock(product) == 1;
        }
        return false;
    }

    @Transactional
    @Override
    public boolean buyProductPessimistic(int id) {
        Product product = productMapper.selectProductXLock(id);
        if (product.getCount() > 0) {
            delay();
            productMapper.decr(product);
        }
        return true;
    }
}
